package com.xinyi.httpdemo.execute;

import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;

import com.alibaba.fastjson.JSON;
import com.xinyi.httpdemo.config.OkHttpConfig;
import com.xinyi.httpdemo.model.HttpHeaders;
import com.xinyi.httpdemo.model.HttpParams;
import com.xinyi.httpdemo.model.RequestConfigData;
import com.xinyi.httpdemo.model.ResponseData;
import com.xinyi.httpdemo.proxy.CallProxy;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * @author 杨耿雷
 * @date 2024/9/24 10:24
 * @description 封装okhttp的同步请求方法
 * <p>
 *      TODO 简易封装，在实际项目中还有异步请求、文件上传、文件下载等操作，可以根据实际情况进行封装。
 */
public class ExecuteAwait {

    private ExecuteAwait() {
    }

    /**
     * 请求执行代理类
     */
    private static CallProxy mCallProxy;

    /**
     * 执行同步请求
     *
     * @param requestConfig 请求配置
     * @return 返回数据请求的响应体
     */
    @WorkerThread
    public static ResponseData execute(RequestConfigData requestConfig) {
        // 初始化请求头和请求参数()
        if (requestConfig.getHeaders() == null) {
            requestConfig.setHeaders(new HttpHeaders());
        }
        if (requestConfig.getParams() == null) {
            requestConfig.setParams(new HttpParams());
        }
        if (requestConfig.getDelayMillis() > 0) {
            // 延迟操作
            try {
                Thread.sleep(requestConfig.getDelayMillis());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        /* TODO 该项目为简单示例，在实际项目中想要更加完善该方法，在正式请求前可以加上缓存策略 */

        mCallProxy = new CallProxy(createCall(requestConfig));

        ResponseData responseData = new ResponseData();
        try (Response response = mCallProxy.execute()) {
            if (response.isSuccessful()) {
                if (response.body() != null) {
                    responseData = JSON.parseObject(response.body().string(), ResponseData.class);
                }
            } else {
                responseData.setMessage("fail");
                responseData.setSuccess(false);
            }
            responseData.setCode(response.code());
            return responseData;
        } catch (IOException e) {
            responseData.setCode(-1);
            responseData.setMessage(e.getMessage());
            responseData.setSuccess(false);
            return responseData;
        }
    }

    /**
     * 创建连接对象
     *
     * @param requestConfig 请求配置
     */
    @NonNull
    private static Call createCall(RequestConfigData requestConfig) {
        // 创建请求对象
        if (requestConfig.getRequest() == null) {
            requestConfig.setRequest(createRequest(requestConfig));
        }

        // 请求头和请求参数拦截处理
        if (OkHttpConfig.getInstance().getInterceptor() != null) {
            OkHttpConfig.getInstance().getInterceptor().interceptArguments(requestConfig.getParams(), requestConfig.getHeaders());
        }

        /* TODO 如有需要可以再添加其他拦截器、 */

        return OkHttpConfig.getInstance().getClient().newCall(requestConfig.getRequest());
    }

    /**
     * 创建请求的对象
     *
     * @param requestConfig 请求配置
     */
    private static Request createRequest(RequestConfigData requestConfig) {
        // 请求地址
        String url = OkHttpConfig.getInstance().getServer().getHost() + requestConfig.getPath();
        // 创建请求构建对象
        Request.Builder requestBuilder = new Request.Builder().url(url);
        // 添加请求头
        addRequestHeader(requestBuilder, requestConfig.getHeaders());
        // 添加请求参数
        addRequestParams(requestBuilder, requestConfig);
        return requestBuilder.build();
    }

    /**
     * 添加请求头
     *
     * @param requestBuilder 请求构建对象
     * @param headers        请求头
     */
    private static void addRequestHeader(Request.Builder requestBuilder, HttpHeaders headers) {
        if (headers.isEmpty()) {
            return;
        }
        for (String key : headers.getKeys()) {
            String value = headers.get(key);
            try {
                requestBuilder.addHeader(key, value);
            } catch (IllegalArgumentException e) {
                Log.e(ExecuteAwait.class.getSimpleName(), "addRequestHeader: " + e.getMessage());
            }
        }
    }

    /**
     * 添加请求参数
     *
     * @param requestBuilder 请求构建对象
     * @param requestConfig  请求配置
     */
    private static void addRequestParams(Request.Builder requestBuilder, RequestConfigData requestConfig) {
        // 根据请求方式添加请求参数
        switch (requestConfig.getMethod()) {
            case GET:
                createNotRequestBody(requestBuilder, requestConfig).method(requestConfig.getMethod().toString(), null);
                break;
            case POST:
                requestBuilder.method(requestConfig.getMethod().toString(), createFormBody(requestConfig.getParams()));
                break;
        }
    }

    /**
     * 组装无请求体的请求
     */
    private static Request.Builder createNotRequestBody(Request.Builder requestBuilder, RequestConfigData requestConfig) {
        // 获取构建的请求配置
        HttpUrl.Builder urlBuilder = requestBuilder.build().url().newBuilder();
        // 添加参数
        if (!requestConfig.getParams().isEmpty()) {
            for (String key : requestConfig.getParams().getKeys()) {
                Object value = requestConfig.getParams().get(key);
                if (value instanceof List) {
                    // 如果这是一个 List 集合
                    List<?> list = ((List<?>) value);
                    for (Object itemValue : list) {
                        if (itemValue == null) {
                            continue;
                        }
                        urlBuilder.addQueryParameter(key, String.valueOf(itemValue));
                    }
                } else if (value instanceof HashMap) {
                    // 如果这是一个 Map 集合
                    Map<?, ?> map = ((Map<?, ?>) value);
                    for (Object itemKey : map.keySet()) {
                        if (itemKey == null) {
                            continue;
                        }
                        Object itemValue = map.get(itemKey);
                        if (itemValue == null) {
                            continue;
                        }
                        urlBuilder.addQueryParameter(key, String.valueOf(itemValue));
                    }
                } else {
                    urlBuilder.addQueryParameter(key, String.valueOf(value));
                }
            }
        }

        // 构建请求地址
        HttpUrl link = urlBuilder.build();
        // 设置请求地址
        requestBuilder.url(link);
        return requestBuilder;
    }

    /**
     * 创建请求体
     *
     * @param params 请求参数
     *               <p>
     * TODO 在真实的带body的请求中，需要根据实际情况来创建请求体, 这里只是简单的创建了一个表单请求体
     */
    private static RequestBody createFormBody(HttpParams params) {
        FormBody.Builder bodyBuilder = new FormBody.Builder();
        if (!params.isEmpty()) {
            for (String key : params.getKeys()) {
                Object value = params.get(key);

                if (!(value instanceof List)) {
                    bodyBuilder.add(key, String.valueOf(value));
                    continue;
                }

                List<?> list = (List<?>) value;
                for (Object itemValue : list) {
                    if (itemValue == null) {
                        continue;
                    }
                    bodyBuilder.add(key, String.valueOf(itemValue));
                }
            }
        }
        return bodyBuilder.build();
    }

    /**
     * 取消请求
     */
    public static void cancel() {
        if (mCallProxy != null) {
            mCallProxy.cancel();
        }
    }
}
